package com.rankeiot.core.inner;

import com.rankeiot.core.EasyCorePlugin;

import com.rankeiot.core.util.SignUtil;
import com.rankeiot.core.util.StringUtil;
import com.rankeiot.core.util.TokenUtil;
import org.sagacity.sqltoy.utils.BeanUtil;
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.UrlResource;


import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.BindException;
import java.net.ServerSocket;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;

import java.util.Map;
import java.util.Properties;

public class ApplicationEnvironmentPreparedEventListener implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {
    public static Integer relPort;
    //父程序PID，用于重启
    public static Long parentPid;
    private static boolean isPortInUse(int port) {
        try (ServerSocket serverSocket = new ServerSocket(port)) {
            return false;
        } catch (IOException e) {
            return true;
        }
    }
    private static Long findParentJavaPid(){
//        ProcessHandle processHandle=ProcessHandle.current();
//        ProcessHandle pp= processHandle.parent().orElse(null);
//        if(pp==null){
//            return null;
//        }
//       // String command=pp.info().command().orElse("").toLowerCase();
//        //通过相同的命令启动
//        if(processHandle.info().commandLine().equals(pp.info().commandLine())){
//            return pp.pid();
//        }
        File file=new File(".restart");
        if(file.exists()){
            Long pid= Long.valueOf(StringUtil.read(file));
            file.delete();
            return pid;
        }
        return null;
    }
    private static int findRandomAvailablePort() {
        try (ServerSocket socket = new ServerSocket(0)) {
            return socket.getLocalPort();
        } catch (IOException e) {
            throw new RuntimeException("Could not find an available port", e);
        }
    }
    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        // event.getSpringApplication().getResourceLoader().getResource("")
        // ApplicationServletEnvironment ae;

        ConfigurableEnvironment environment = event.getEnvironment();



        Map<String, Object> defaultConfig = new HashMap<>();



        String salt=environment.getProperty("spring.salt");
        if(StringUtil.isEmpty(salt)) {
            String applicationName = environment.getProperty("spring.application.name");
            if (StringUtil.isEmpty(applicationName)) {
                if(StringUtil.isEmpty(TokenUtil.getGlobalSalt())) {
                    //已经有了GlobalSalt,不改变否则直接设置
                    SpringApplication application = event.getSpringApplication();
                    applicationName = application.getMainApplicationClass().getName();
                    TokenUtil.setGlobalSalt(StringUtil.base62(applicationName));
                }
            }else{
                TokenUtil.setGlobalSalt(StringUtil.base62(applicationName));
            }
        }else{
            TokenUtil.setGlobalSalt(salt);
        }
        //sqltoy
        defaultConfig.put("spring.sqltoy.sqlResourcesDir", "classpath:mapper");
        // defaultConfig.put("spring.sqltoy.typeHandler","com.rankeiot.core.sqltoy.JsonTypeHandler");
        defaultConfig.put("spring.sqltoy.cacheType", "caffeine");

        //jackson
        defaultConfig.put("spring.jackson.default-property-inclusion", "non_null");




        //doc
        defaultConfig.put("knife4j.enable", "true");
        defaultConfig.put("knife4j.setting.language", "zh_cn");
        defaultConfig.put("knife4j.setting.enable-filter-multipart-apis", "true");
        defaultConfig.put("knife4j.setting.enable-group", "true");
        defaultConfig.put("knife4j.setting.enable-dynamic-parameter", "true");
        defaultConfig.put("knife4j.openapi.title", "接口文档");
        defaultConfig.put("knife4j.openapi.group.default.group-name", "默认分组");
        defaultConfig.put("knife4j.openapi.group.default.api-rule", "annotation");
        defaultConfig.put("knife4j.openapi.group.default.api-rule-resources[0]", "io.swagger.annotations.Api");

        //加载默认配置文件
        // YamlPropertiesFactoryBean
        try {
            Enumeration<URL> configResources = Thread.currentThread()
                    .getContextClassLoader()
                    .getResources("application-plugin.yml");
            while (configResources.hasMoreElements()) {
                URL url = configResources.nextElement();
                YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
                factory.setResources(new UrlResource(url));
                // factory.afterPropertiesSet();
                Properties props = factory.getObject();
                for (Object key : props.keySet()) {
                    String keyStr = key.toString();
                    if (environment.getProperty(keyStr) == null) {
                        defaultConfig.put(key.toString(), props.getProperty(key.toString()));
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        boolean isDev = "dev".equals(environment.getProperty("spring.profiles.active"));
        defaultConfig.put("isDev", isDev);
        if (isDev) {
            EasyCorePlugin.isDev = true;
            defaultConfig.put("spring.sqltoy.debug", "true");

        }else{
            if(environment.getProperty("spring.sqltoy.scriptCheckIntervalSeconds")==null){
                defaultConfig.put("spring.sqltoy.scriptCheckIntervalSeconds","-1");
            }
        }

        outFlag:
        for (PropertySource ps : environment.getPropertySources()) {
            if (ps instanceof MapPropertySource) {
                MapPropertySource mps = (MapPropertySource) ps;
                for (String n : mps.getPropertyNames()) {
                    if (n.startsWith("spring.datasource")) {
                        EasyCorePlugin.hasDataSource = true;
                        break outFlag;
                    }
                }
            }
        }
        environment.getPropertySources().addLast(new MapPropertySource("default", defaultConfig));

        Integer port=environment.getProperty("server.port",Integer.class);
        //设置port,如果port占用，查看程序是不是java的进程，如果是，将本服务换为新端口后结束老进程
        if(port==null){
            //未设置port
            relPort=8080;
        }else{
            //替换设置
            relPort=port;
        }
        if(isPortInUse(relPort)){
            //是否为应用内重启,如何认定？restart_by=pid
            parentPid=findParentJavaPid();
            if(parentPid!=null){
                //切换端口
                Integer newPort=findRandomAvailablePort();
                Map<String, Object> map = new HashMap<>();
                map.put("server.port", newPort); // 将端口改为8081
                MapPropertySource propertySource = new MapPropertySource("customPortSource", map);
                // 将自定义属性源添加到环境中
                environment.getPropertySources().addFirst(propertySource);
            }

        }else{
            relPort=null;
        }
    }
}
